/******************************************************************************
*	cmMutex.c	Code file of CM Mutex Module.
*
*	coypright (C) 2009 Ding Lixing
*
******************************************************************************/

#include "cm.h"

extern cmTASK *cmTaskGetCurrent(void);
extern int cmTaskPriorityRuntimeSet(cmTASK * task, unsigned char priority);

static int mutexPrePost(cmOBJ *obj, void *param)
{
    cmTASK *self;
    cmMUTEXDATA *data;

    (void)param;
    self = cmTaskGetCurrent();
    data = (cmMUTEXDATA *)(obj->data);
    
    if(data->owner != self){
        return CM_ERR_MutexNotOwner;
    }else{
        if(--data->nesting == 0){
            data->owner = (cmTASK *)0;
            if((obj->opt & CM_OP_CEIL) && (self->prioritySet != self->priority)){
                cmTaskPriorityRuntimeSet(self, self->prioritySet);
            }
        }
        return data->nesting;
    }
}

static int mutexPrePend(cmOBJ *obj, void *param)
{
    cmTASK *self;
    cmMUTEXDATA *data;


    (void)param;
    self = cmTaskGetCurrent();
    data = (cmMUTEXDATA *)(obj->data);

    if(data->owner != self && data->owner != (cmTASK *)0){
        return CM_ERR_MutexNotFree;
    }else{
        data->owner = self;
        if(data->nesting++ < 1){
            if((obj->opt & CM_OP_CEIL) && (data->ceil < self->priority)){
                cmTaskPriorityRuntimeSet(self, data->ceil);
            }
        }
    }

    return 0;
}

int cmMutexInit(cmMUTEX * mutex, unsigned int opt, unsigned char ceil)
{
    if((opt & ~CM_OP_MASK) || (ceil >= CM_CFG_TASK_PRIO_LEVEL)){
        return CM_ERR_InvalidArgument;
    }

    mutex->data.owner = (cmTASK *)0;
    mutex->data.ceil = ceil;
    mutex->data.nesting = 0;

    return cmTaskObjInit(&mutex->obj, CM_OBJ_MUTEX, opt, mutexPrePost, mutexPrePend, (void*)&mutex->data);
}

int cmMutexLock(cmMUTEX *mutex, unsigned int tout)
{
    return cmTaskObjPend(&mutex->obj, tout, (void*)0);
}

int cmMutexUnlock(cmMUTEX *mutex)
{
    return cmTaskObjPost(&mutex->obj, (void*)0);
}

